import 'dart:convert';
import 'package:dog_read/pages/utils/common_utils.dart';
import 'package:flutter/material.dart' as Ma;
import 'package:dio/dio.dart';
import 'package:html/parser.dart' show parse;
import 'package:html/dom.dart';
import 'package:dog_read/models/book/book_model.dart';
import 'package:dog_read/db/book_db.dart' show bookDb;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sqflite/sqlite_api.dart';


class BiqugeSpider {
  static String baseUrl = "https://www.biquge.com.cn";

  static getCategoryBooks() async{
    String responseData = await getPageContent();
    Document document = parse(responseData);
    // Response resp = await Dio().get(baseUrl);
    // String data = resp.data;
    // 解析页面元素
    // Document documnet = parse(data);
    // 解析book相关信息
    List<Element> bookTypes = document.querySelectorAll(".novelslist");
    List<Element> bookFirstRow = bookTypes[0].querySelectorAll(".content");
    bookFirstRow.addAll(bookTypes[1].querySelectorAll(".content"));
    List result = [];
    bookFirstRow.forEach((element) { 
      String bookType =  element.getElementsByTagName("h2")[0].innerHtml;
      Element topBook = element.getElementsByClassName("top")[0];
      Map topContent = {
        "imgUrl": topBook.getElementsByTagName("img")[0].attributes["src"],
        "bookUrl": baseUrl + topBook.getElementsByTagName("a")[0].attributes["href"],
        "title": topBook.getElementsByTagName("dt")[0].getElementsByTagName("a")[0].innerHtml,
        "description": topBook.getElementsByTagName("dd")[0].innerHtml
      };
      List<Element> otherBooks = element.getElementsByTagName("li");
      List other = otherBooks.map((e){
        return {
          "title": e.getElementsByTagName("a")[0].innerHtml,
          "author": e.innerHtml.split(r"/").removeLast(),
          "bookUrl": baseUrl + e.getElementsByTagName("a")[0].attributes["href"]
        };
      }).toList();  

      Map tempResult = {
        "bookType": bookType,
        "topBook": topContent,
        "otherBooks": other
      };
      result.add(tempResult);
    });
    return result;
  }

  static search(String searchContent) async {
    String url = "https://www.biquge.com.cn/search.php?q=" + searchContent;
    // 获取书籍的详情信息
    Response resp = await Dio().get(url);
    String data = resp.data;
    // 解析页面元素
    Document documnet = parse(data);
    // 解析book相关信息
    List<Element> resultList = documnet.getElementsByClassName("result-item result-game-item");
    List result = [];
    for(var item in resultList){
      String bookCoverUrl = item.getElementsByTagName("img")[0].attributes["src"];
      String bookTitle = item.getElementsByTagName("span")[0].innerHtml;
      String bookUrl = item.querySelector(".result-game-item-title-link").attributes["href"];
      List<Element> spans = item.querySelector(".result-game-item-info").getElementsByTagName("span");
      String author = spans[1].innerHtml;
      String latestChapter = item.querySelector(".result-game-item-info").getElementsByTagName("a")[0].innerHtml;
      result.add(
        {
          "bookCoverUrl": bookCoverUrl,
          "bookTitle": bookTitle,
          "bookUrl": baseUrl + bookUrl,
          "author": author,
          "latestChapter": latestChapter
        }
      );
    }
    return result;
  }

  static getPageContent() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String responseData = prefs.getString("biqugeHome") ?? null;
    int biquegeSaveTime = prefs.getInt("biqugeSaveTime") ?? null;
    if (responseData == null ||
        biquegeSaveTime == null ||
        biquegeSaveTime <
            (DateTime.now().millisecondsSinceEpoch - 2 * 3600 * 1000)) {
      try {
        Response response = await Dio().get(baseUrl);
        responseData = response.data;
      } catch (e, s) {
        print('Exception details:\n $e');
        print('Stack trace:\n $s');
      }
      prefs.setString("biqugeHome", responseData);
      prefs.setInt("biqugeSaveTime", DateTime.now().millisecondsSinceEpoch);
    }
    return responseData;
  }

  static _getRecommend() async {
    String responseData = await getPageContent();
    Document document = parse(responseData);

    List hotContentList = <BookModel>[];
    Element hotContent = document.getElementById("hotcontent");
    List<Element> hotItems = hotContent.getElementsByClassName("item");
    for (var item in hotItems) {
      String imageUrl = item.getElementsByTagName("img")[0].attributes["src"];
      String bookUrl =
          baseUrl + item.getElementsByTagName("a")[0].attributes["href"];
      String title = item.getElementsByTagName("dt")[0].getElementsByTagName("a")[0].innerHtml;
      String author = item.getElementsByTagName("dt")[0].getElementsByTagName("span")[0].innerHtml;
      String description = item.getElementsByTagName("dd")[0].innerHtml;

      hotContentList.add(BookModel.fromJson({
        "imageUrl": imageUrl,
        "bookUrl": bookUrl,
        "title": title,
        "description": description,
        "author": author
      }));
    }
    return hotContentList;
  }

  static _getStrongRecommend() async {
    String responseData = await getPageContent();
    Document document = parse(responseData);

    List hotContentList = <BookModel>[];
    Element hotContent = document.querySelector(".r");
    List<Element> hotItems = hotContent.getElementsByTagName("li");
    for (var item in hotItems) {
      List<Element> spanElements = item.getElementsByTagName("span");
      String bookType = spanElements[0].innerHtml;
      String title = spanElements[1].getElementsByTagName("a")[0].innerHtml;
      String author = spanElements[2].innerHtml;
      String bookUrl = baseUrl + spanElements[1].getElementsByTagName("a")[0].attributes["href"];

      hotContentList.add(BookModel.fromJson({
        "bookUrl": bookUrl,
        "title": title,
        "author": author,
        "bookType": bookType
      }));
    }
    return hotContentList;
  }

  static getAllRecommend() async {
    return {
      "hotRecommend": await _getRecommend(),
      "strongRecommend": await _getStrongRecommend()
    };
  }

  static getLatestBook() async {
    String responseData = await getPageContent();
    Document document = parse(responseData);
    // 获取书籍的详情信息
    // Response resp = await Dio().get(baseUrl);
    // String data = resp.data;
    // 解析页面元素
    // Document documnet = parse(data);
    // 解析book相关信息
    List<Element> latestUpdatebooks = document
        .getElementById("newscontent")
        .querySelector(".l")
        .getElementsByTagName('li');
    List latestUpdatebookList = [];
    for (var item in latestUpdatebooks) {
      latestUpdatebookList.add({
        "type": item.querySelector(".s1").innerHtml,
        "title":item.querySelector(".s2").getElementsByTagName("a")[0].innerHtml,
        "url": baseUrl + item.querySelector(".s2").getElementsByTagName("a")[0].attributes["href"],
        "latestChapterName":item.querySelector(".s3").getElementsByTagName("a")[0].innerHtml,
        "latestChapterUrl": baseUrl +item.querySelector(".s3").getElementsByTagName("a")[0].attributes["href"],
        "author": item.querySelector(".s4").innerHtml,
        "updateTime": item.querySelector(".s5").innerHtml
      });
    }
    List<Element> latestRecordBooks = document
        .getElementById("newscontent")
        .querySelector(".r")
        .getElementsByTagName('li');
    List latestRecordBookList = [];
    for (var item in latestRecordBooks) {
      latestRecordBookList.add({
        "type": item.querySelector(".s1").innerHtml,
        "title":item.querySelector(".s2").getElementsByTagName("a")[0].innerHtml,
        "url": baseUrl + item.querySelector(".s2").getElementsByTagName("a")[0].attributes["href"],
        "updateTime": item.querySelector(".s5").innerHtml
      });
    }
    // print(latestRecordBookList);
    Map result = {
      "latestRecordBookList": latestRecordBookList,
      "latestUpdatebookList": latestUpdatebookList
    };
    return result;
  }

  static getBookDetails(String bookUrl) async {
    Database db = await bookDb;
    // 先查表
    List books = await db.rawQuery("select * from book where book_url=?", [bookUrl]);
    if(books.isNotEmpty){
      Map bookInfo = Map.from(books[0]);
      int createTime = DateTime.parse(bookInfo["create_time"]).millisecondsSinceEpoch;
      if(DateTime.now().millisecondsSinceEpoch - createTime < 24*3600*1000){
        bookInfo["recommend_books"] = json.decode(bookInfo["recommend_books"]);
        // 查出对应的章节
        List chapterList = await db.rawQuery("select * from bookChapter where book_id=? order by chapter_id ASC", [books[0]["id"]]);
        bookInfo["chapterList"] = chapterList;
        print("缓存获取: $bookUrl");
        return bookInfo;
      }
    }

    // 获取书籍的详情信息
    Response resp = await Dio().get(bookUrl);
    String data = resp.data;
    // 解析页面元素
    Document documnet = parse(data);
    // 解析book相关信息
    String bookCoverUrl = documnet.querySelector("#fmimg").getElementsByTagName("img")[0].attributes["src"];
    Element mainInfo = documnet.getElementById("maininfo");
    String bookTitle = mainInfo.getElementsByTagName("h1")[0].innerHtml;
    String bookIntro = mainInfo.querySelector("#intro").innerHtml;
    String bookAuthor = mainInfo.getElementsByTagName("p")[0].innerHtml.replaceAll("&nbsp;", "").split("：").reversed.toList()[0];
    String bookStatuString = mainInfo.getElementsByTagName("p")[1].innerHtml.split(",")[0].replaceAll("&nbsp;", "").split("：").reversed.toList()[0];
    String bookUpdateTime = mainInfo.getElementsByTagName("p")[2].innerHtml.split("：").reversed.toList()[0];
    String latestChapter = mainInfo.getElementsByTagName("p")[3].getElementsByTagName("a")[0].innerHtml;
    // 推荐阅读信息
    List<Element> recommendReadBooks = documnet.getElementById("listtj").getElementsByTagName("a");
    List bookList = [];
    for (var item in recommendReadBooks) {
      bookList.add({
        "url": "https://www.biquge.com.cn" + item.attributes["href"],
        "title": item.innerHtml,
      });
    }
    // 解析章节相关信息
    List<Element> chapterElements = documnet.getElementById("list").getElementsByTagName("a");
    List chapterList = [];
    for (var item in chapterElements) {
      chapterList.add({
        "title": item.innerHtml,
        "chapter_url": baseUrl + item.attributes["href"]
      });
    }
    Map bookInfo = {
      "book_url": bookUrl,
      "recent_update_time": bookUpdateTime,
      "image_url": bookCoverUrl,
      "title": bookTitle,
      "description": bookIntro,
      "author":bookAuthor,
      "status": bookStatuString,
      "latest_chapter": latestChapter,
      "recommend_books": bookList,
      "chapterList": chapterList
    };
    // 保存起来
    await db.transaction((txn) async {
      int bookId = await txn.rawInsert(
      """insert or replace into book(title,author,description,image_url,book_url,
      recommend_books,status, total_chapter,latest_chapter,recent_update_time,create_time)
      values(?,?,?,?,?,?,?,?,?,?,?)""",
      [bookTitle,bookAuthor,bookIntro,bookCoverUrl,bookUrl,json.encode(bookList),
      bookStatuString,chapterList.length,latestChapter,bookUpdateTime,DateTime.now().toString()]
      );
      bookInfo["id"] = bookId;
      for (var i = 0; i < chapterList.length; i++) {
        Map element = chapterList[i];
        await txn.rawInsert(
            "insert or replace into bookChapter(book_id,chapter_id,title,chapter_url) values(?,?,?,?)",
            [bookId, i, element["title"], element["chapter_url"]]
          );
      }
    });
    return bookInfo;
  }

  static getChapterContent(String chapterUrl) async {
    // 获取小说内容
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String resutlStr = prefs.getString(chapterUrl);
    if (resutlStr != null) {
      return json.decode(resutlStr);
    }
    Ma.debugPrint("开始获取章节: $chapterUrl");
    Response resp = await Dio().get(chapterUrl, options: Options(sendTimeout: 20));
    String data = resp.data;
    // 解析页面元素
    Document documnet = parse(data);
    // 解析章节内容页面信息
    String chapterContent = documnet.getElementById("content").innerHtml;
    List<Element> pnChapters =
        documnet.querySelector(".bottem1").getElementsByTagName("a");
    String preChapterUrl = pnChapters[0].attributes["href"];
    String nextChapterUrl = pnChapters[2].attributes["href"];
    String chapterTitle = documnet
        .querySelector(".bookname")
        .getElementsByTagName("h1")[0]
        .innerHtml;

    Map result = {
      "preChapterUrl": preChapterUrl.contains(".html") ? baseUrl + preChapterUrl : null,
      "nextChapterUrl":  nextChapterUrl.contains(".html") ? baseUrl + nextChapterUrl : null,
      "chapterContent": chapterContent
          .replaceAll(r"&nbsp;", " ")
          .replaceAll(r"<br><br>", "\n")
          .replaceAll(r"<br>", "\n")
          .replaceAll("\n\n", "\n"),
      "chapterTitle": chapterTitle
    };
    await prefs.setString(chapterUrl, json.encode(result));
    Ma.debugPrint("获取成功: $chapterTitle => $chapterUrl");
    return result;
  }
}
